1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  
15  package com.google.common.collect;
16  
17  import static com.google.common.base.Preconditions.checkArgument;
18  
19  import com.google.common.annotations.GwtCompatible;
20  
21  import java.util.EnumMap;
22  import java.util.Iterator;
23  
24  /**
25   * Multiset implementation backed by an {@link EnumMap}.
26   * 
27   * <p>See the Guava User Guide article on <a href=
28   * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
29   * {@code Multiset}</a>.
30   *
31   * @author Jared Levy
32   * @since 2.0 (imported from Google Collections Library)
33   */
34  @GwtCompatible(emulated = true)
35  public final class EnumMultiset<E extends Enum<E>> extends AbstractMapBasedMultiset<E> {
36    /** Creates an empty {@code EnumMultiset}. */
37    public static <E extends Enum<E>> EnumMultiset<E> create(Class<E> type) {
38      return new EnumMultiset<E>(type);
39    }
40  
41    /**
42     * Creates a new {@code EnumMultiset} containing the specified elements.
43     *
44     * <p>This implementation is highly efficient when {@code elements} is itself a {@link
45     * Multiset}.
46     *
47     * @param elements the elements that the multiset should contain
48     * @throws IllegalArgumentException if {@code elements} is empty
49     */
50    public static <E extends Enum<E>> EnumMultiset<E> create(Iterable<E> elements) {
51      Iterator<E> iterator = elements.iterator();
52      checkArgument(iterator.hasNext(), "EnumMultiset constructor passed empty Iterable");
53      EnumMultiset<E> multiset = new EnumMultiset<E>(iterator.next().getDeclaringClass());
54      Iterables.addAll(multiset, elements);
55      return multiset;
56    }
57    
58    /**
59     * Returns a new {@code EnumMultiset} instance containing the given elements.  Unlike
60     * {@link EnumMultiset#create(Iterable)}, this method does not produce an exception on an empty
61     * iterable.
62     * 
63     * @since 14.0
64     */
65    public static <E extends Enum<E>> EnumMultiset<E> create(Iterable<E> elements, Class<E> type) {
66      EnumMultiset<E> result = create(type);
67      Iterables.addAll(result, elements);
68      return result;
69    }
70  
71    private transient Class<E> type;
72  
73    /** Creates an empty {@code EnumMultiset}. */
74    private EnumMultiset(Class<E> type) {
75      super(WellBehavedMap.wrap(new EnumMap<E, Count>(type)));
76      this.type = type;
77    }
78  }
79